﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using System.Text;

namespace QW.Found.JwtAuthorize
{
    /// <summary>
    /// JwtBearer扩展
    /// </summary>
    public static class JwtBearerExtension
    {
        /// <summary>
        /// Api引入Jwt
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        /// <param name="permissionAction">二次验证</param>
        /// <returns></returns>
        public static AuthenticationBuilder AddApiJwtAuthorize(this IServiceCollection services, JWTConfig config, Func<AuthorizationHandlerContext, bool> permissionAction = null)
        {
            if (string.IsNullOrWhiteSpace(config.Secret)) { throw new Exception("密钥不可以为空"); }
            var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.Secret));
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = config.Issuer,
                ValidateAudience = true,
                ValidAudience = config.Audience,
                ClockSkew = TimeSpan.Zero,
                RequireSignedTokens = true,   //token必须签名
                RequireExpirationTime = true,  //token必须包含有效期
                ValidateLifetime = true,   //验证token有效期
            };
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);  //加密方式选用HS256

            var permissionRequirement = new JwtAuthorizationRequirement(config.Issuer, config.Audience, JWTConfig.DEFAULT_SCHEME, signingCredentials);
            permissionRequirement.ValidatePermission = permissionAction;

            services.AddAuthorizationCore(opt =>
            {
                opt.AddPolicy(JWTConfig.POLICY_NAME, policy => policy.Requirements.Add(permissionRequirement));

                //opt.AddPolicy("OrPolicy", p => { p.RequireRole("Admin", "User").Build(); }); // 或条件达成
                //opt.AddPolicy("AndPolicy", p => { p.RequireRole("Admin").RequireRole("User").Build(); }); // 与条件达成
            });
            var result = services.AddAuthentication(opt => { opt.DefaultScheme = JWTConfig.DEFAULT_SCHEME; })
                .AddJwtBearer(JWTConfig.DEFAULT_SCHEME, opt =>
                {
                    opt.RequireHttpsMetadata = config.IsHttps;
                    opt.TokenValidationParameters = tokenValidationParameters;
                    /*
                    opt.Events = new JwtBearerEvents()
                    {
                        OnMessageReceived = context =>
                        {
                            //接收url传参作token使用
                            context.Token = context.Request.Query["access_token"];
                            return Task.CompletedTask;
                        }
                    };
                    */

                    // 增加验证器，用于验证前解密，需要BuildJwtToken时先加密Token
                    // opt.SecurityTokenValidators.Clear();
                    // opt.SecurityTokenValidators.Add(new AESTokenValidator());
                });
            services.AddSingleton(permissionRequirement);
            services.AddSingleton(config);
            services.AddSingleton<ITokenBuilder, TokenBuilder>();
            //注入登录用户提供者(一个基础登录用户信息提供者)
            services.AddSingleton<PrincipalUserProvider>();
            //注入权限验证处理器
            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
            return result;
        }
    }
}
